install.packages(c('ggmap',"leaflet", 'leaflet.extras', 'crosstalk', 'htmlwidgets'))Mapping
Packages you might need to install:
Making maps
Since the ACLED (and many other event data sets) are already coded by location, it can be useful to use a map to present results.
Getting Data
We’ll import some data for Brazil
library(acled.api)
library(tidyverse)
library(ggmap)
events<-acled.api(
email.address = Sys.getenv("ACLED_EMAIL"),
access.key = Sys.getenv("ACLED_API_KEY"),
start.date = "2024-01-01",
end.date = Sys.Date(),
country = "Brazil",
all.variables = TRUE
)
events<-events|>
# only keeping events with high level of location precision
filter(geo_precision == 1) |>
mutate(latitude = as.numeric(latitude),
longitude = as.numeric(longitude),
event_date = as.Date(event_date)
)Generating a static map
Now we’ll get a bounding box for these results. The bounding box will control the portion of the world map we retrieve:
events_by_location<- events|>
count(latitude, longitude, event_type)
bbox<-make_bbox(longitude, latitude, data=events_by_location)Next, we’ll retrieve some map tiles from Stadia. This API is free to use for non-commericial applications, but we do need to sign up and set an API key. You can sign up here:
https://client.stadiamaps.com/signup/
After that, you should be able to access an API key here:
https://client.stadiamaps.com/dashboard/#/property/17475/
Finally, you can set your key in R by running:
register_stadiamaps(key = "YOUR API KEY HERE", write=TRUE)Now, we’ll load the data. You get an error message about needing a smaller mapping space here. You can lower the zoom size (or leave this argumnent out entirely to set it automatically) but you might lose some resolution as a result.
map<-get_map(bbox, source='stadia',
# remove this argument or lower the value to get faster results
zoom=5,
maptype='stamen_terrain')Since this can take a minute to load, you might want to save your results to a file so you can reuse them in a later session without having to wait for everything to download all over again.
save(map, file = "stamen_map.RData")Just running the ggmap argument will return the mapping space itself. Note that, if some stuff is cut off, you can change the values of bbox to encompass a smaller or larger space.
load(file = "stamen_map.RData")
ggmap(map)We want to add some additional aesthetics to our map. Using a similar approach to the one we use for making a ggplot object: we’ll take the base map, and then gradually add additional geometries to it. Here, we’re adding a point for each event in the event data with geom_point. Since we already have coordinates for each event, we can just use the latitude and longitude arguments to set the location of each point:
plot <- ggmap(map) +
geom_point(
data = events_by_location,
aes(
x = longitude,
y = latitude))
plotI can make some additional modifications here: some locations had multiple events within the last week, so it might make sense to rescale each point by the number of events that occurred at each location. I might also want to color-code each point to indicate the type of event it represents. Finally, I’ll add a title, and descriptive labels to each of the legends:
plot <- ggmap(map) +
geom_point(
data = events_by_location,
aes(
x = longitude,
y = latitude,
color = event_type,
size = n
),
alpha = .8
) +
ggtitle("Events in Brazil since in 2024") +
labs(color = "event type", size = 'number of events')
plotSaving the result
Now I will want to save my plot, ideally at a relatively high resolution so it looks good in a presentation. I can use ggsave to save the plot object to a file called mapped.tiff. Setting dpi=1200 here ensures that I get a high resolution image:
ggsave(plot, file='mapped.tiff', dpi = 1200, height=7, width=7)We can also facet our map to show different subsets of the data by using the facet_wrap argument. For instance, if I wanted to show events for each month in this data, I could do that by first getting a count of events-per-month:
events_by_location_and_date<- events|>
# get the month for each event
mutate(month = floor_date(as.Date(event_date), unit='month')) |>
# count events per location per month
count(latitude, longitude, event_type, month)And then creating the same plot but with the facet_wrap argument specified:
plot_monthly <- ggmap(map) +
geom_point(
data = events_by_location_and_date,
aes(
x = longitude,
y = latitude,
color = event_type,
size = n
),
alpha = .8
) +
ggtitle("Events in Brazil in 2024") +
labs(color = "event type", size = 'number of events') +
# separate the plot into facets
facet_wrap(~month)
ggsave(plot_monthly, file='mapped_monthly.tiff', dpi = 1200, height=7, width=7)Interactive Map with Leaflet
We can use leaflet to create an interactive world map with our event data. The addProviderTiles function will draw in data from any of a number of sources. Some of these require registration, but the OpenStreetMap ones should be free. (View other options here)
library(leaflet)
# get a base map
base_map <- leaflet() |>
addProviderTiles(providers$OpenStreetMap.Mapnik)
base_mapNow, we can add point to our map using the addCircles function. We’ll also create a color palette that color-codes points by event-type using the colorFactor function and a legend with the addLegend function.
Note here that we’re using all of the event data, instead of the data that’s aggregated by location. The reason for this will become clear in a moment.
pal <- colorFactor(
palette = 'Dark2',
domain = events$event_type
)
event_map<-base_map|>
addCircles(data = events,
lng=~longitude,
lat=~latitude,
color=~pal(event_type)
)|>
# add a legend to the bottom left
addLegend(position = "bottomleft", pal=pal, values=events$event_type)
event_mapNow we can go a step further by adding the contents of the notes column as a popup over each point. You should be able to click on a point and see a description of the event at that location:
event_map <- base_map |>
addCircles(
data = events,
lng = ~ longitude,
lat = ~ latitude,
popup = ~ notes,
color = ~ pal(event_type)
) |>
# add a legend to the bottom left
addLegend(position = "bottomleft",
pal = pal,
values = events$event_type)
event_mapSaving results
We can export our results to file with the saveWidget function. Unfortunately, you can’t embed this in a powerpoint, but you could show it on your local device. Alternatively, you could just screenshot a particular view of the map.
library(htmlwidgets)
saveWidget(event_map, file="events.html")Adding a filter
library(leaflet.extras)
library(crosstalk)
# make shared data
events_sd<-SharedData$new(events)
# create a new map using the shared data
event_map <- base_map |>
addCircles(
data = events_sd,
lng = ~ longitude,
lat = ~ latitude,
popup = ~ notes,
color = ~ pal(event_type),
group = "event_markers"
) |>
# add a legend to the bottom left
addLegend(position = "bottomleft",
pal = pal,
values = events_sd$event_type)
#add a column with a selection filter
bscols(
widths=c(2, 10),
list(filter_select("type",'event', events_sd, ~event_type)),
event_map
)